package com.property.manage.service.parking;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.guardchina.framework.mybatis.model.CustomPage;
import com.guardchina.framework.util.exception.BusinessException;
import com.guardchina.framework.util.exception.SystemException;
import com.guardchina.framework.util.utils.DateUtil;
import com.guardchina.framework.util.utils.NumberToCn;
import com.property.manage.dao.flowingWater.FlowingWaterMapper;
import com.property.manage.dao.parking.ParkingRentMapper;
import com.property.manage.dao.parking.ParkingRentPayRecordMapper;
import com.property.manage.enums.WalletType;
import com.property.manage.model.flowingWater.FlowingWaterEntity;
import com.property.manage.model.parking.*;
import com.property.manage.model.print.PayBillVo;
import com.property.manage.model.system.SysSet;
import com.property.manage.model.system.User;
import com.property.manage.service.flowingWater.FlowingWaterService;
import com.property.manage.service.flowingWater.WalletService;
import com.property.manage.service.system.SnowflakeIdWorker;
import com.property.manage.service.system.UserService;
import com.property.manage.util.ExportUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.FileInputStream;
import java.io.IOException;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Optional;

/**
 * 描述
 *
 * @author lwb
 * @since 2020/9/11
 */
@Service
@Slf4j
public class ParkingRentService {

    private ParkingRentMapper parkingRentMapper;

    private ParkingRentDeductionService parkingRentDeductionService;

    private UserService userService;

    private ParkingRentPayRecordService parkingRentPayRecordService;

    private ParkingRentArrearsService parkingRentArrearsService;

    private SnowflakeIdWorker snowflakeIdWorker;

    private WalletService walletService;

    @Value("${daily.running.parkingRentPayRecod}")
    private String tempFilePath;

    @Value("${timed.patee}")
    private String patee;

    @Value("${timed.receiveUnit}")
    private String receiveUnit;

    @Autowired
    private FlowingWaterService flowingWaterService;

    @Autowired
    private FlowingWaterMapper flowingWaterMapper;

    public CustomPage<ParkingRentVo> page(Long pageNo, Long pageSize, Integer villageId, Integer building, Integer unit, String roomNumber) {
        Page<ParkingRentVo> page = new Page<>(pageNo, pageSize);

        IPage<ParkingRentVo> resultPage = parkingRentMapper.page(page, villageId, building, unit, roomNumber);

        return new CustomPage<>(resultPage);
    }


    public void add(Integer buildingId, String userName, String phone, Integer parkingNum, String parkingNo, BigDecimal rentFee, LocalDate startDate, LocalDate endDate, String cardNo) {

        ParkingRentEntity existEntity = findRentingByBuildingId(buildingId);
        if (existEntity != null) {
            throw new BusinessException("该房号已有在租车位", String.format("buildingId[%s]", buildingId));
        }

        ParkingRentEntity rentEntity = new ParkingRentEntity();

        rentEntity.setBuildingId(buildingId);
        rentEntity.setUserName(userName);
        rentEntity.setPhone(phone);
        rentEntity.setParkingNum(parkingNum);
        rentEntity.setParkingNo(parkingNo);
        rentEntity.setRentFee(rentFee);
        rentEntity.setStartDate(startDate);
        rentEntity.setEndDate(endDate);
        rentEntity.setState(ParkingRentEntity.STATE_RENTING);
        rentEntity.setCardNo(cardNo);
        parkingRentMapper.insert(rentEntity);
    }

    public void update(Integer id, Integer buildingId, String userName, String phone, Integer parkingNum, String parkingNo, BigDecimal rentFee, LocalDate startDate, LocalDate endDate, String cardNo) {
        ParkingRentEntity existEntity = findRentingByBuildingId(buildingId);
        if (existEntity != null && !existEntity.getBuildingId().equals(buildingId)) {
            throw new BusinessException("该房号已有在租车位", String.format("id[%s], buildingId[%s]", id, buildingId));
        }

        ParkingRentEntity rentEntity = new ParkingRentEntity();

        rentEntity.setId(id);
        rentEntity.setBuildingId(buildingId);
        rentEntity.setUserName(userName);
        rentEntity.setPhone(phone);
        rentEntity.setParkingNum(parkingNum);
        rentEntity.setParkingNo(parkingNo);
        rentEntity.setRentFee(rentFee);
        rentEntity.setStartDate(startDate);
        rentEntity.setEndDate(endDate);
        rentEntity.setCardNo(cardNo);
        parkingRentMapper.updateById(rentEntity);
    }

    public void delete(Integer id) {
        ParkingRentEntity rentEntity = new ParkingRentEntity();
        rentEntity.setId(id);

        rentEntity.setState(ParkingRentEntity.STATE_DELETED);

        parkingRentMapper.updateById(rentEntity);
    }

    public void deduction(Integer userId, Integer villageId, Integer year, Integer month) {

        log.info("userId[{}], villageId[{}], year[{}], month[{}]车位租金划扣", userId, villageId, year, month);
        Optional<ParkingRentDeductionEntity> optional = parkingRentDeductionService.find(villageId, year, month);
        optional.ifPresent(entity -> {
            throw new BusinessException(month + "月份已划扣，请勿重复划扣");
        });

        User user = userService.getUser(userId);

        List<ParkingRentEntity> parkingRentEntities = getByVillageId(villageId);

        parkingRentDeductionService.add(villageId, year, month);


        String yearMonth = year + (month >= 10 ? month + "" : "0" + month);

        String remark = yearMonth + "车位租金批量划扣";

        for (ParkingRentEntity entity : parkingRentEntities) {

            try {
                String billNo = snowflakeIdWorker.nextId() + "";
                parkingRentPayRecordService.pay(user, entity.getBuildingId(), entity.getId(), entity.getRentFee(), BigDecimal.ZERO, entity.getRentFee(), BigDecimal.ZERO, SysSet.PAY_TYPE_CODE_FOUR, remark, billNo, ParkingRentPayRecordEntity.TYPE_NORMAL, entity.getRentFee(), FlowingWaterEntity.OTHER_TYPE_NORMAL);

                //创建流水
                //User user, Integer buildingId, BigDecimal shouldPay, BigDecimal realFee, BigDecimal subtractFee, BigDecimal preStorage, BigDecimal expenditure, BigDecimal cash, BigDecimal small, String listOfCharges, Integer type, String explain, String remarks, String payType, String billNo, Byte otherType
//                FlowingWaterEntity flowingWaterEntity = flowingWaterService.createFlowingWaterEntityByBuildingId(user, entity.getBuildingId(), entity.getRentFee(), entity.getRentFee(), BigDecimal.ZERO, entity.getRentFee(), BigDecimal.ZERO, BigDecimal.ZERO, BigDecimal.ZERO, "车位租金划扣", 1, "", "批量划扣", SysSet.PAY_TYPE_CODE_FOUR, billNo, FlowingWaterEntity.OTHER_TYPE_NORMAL);
//                flowingWaterMapper.insert(flowingWaterEntity);

            } catch (BusinessException e) {
                log.error("车位租金划扣失败：rentId[{}], year[{}], month[{}]", entity.getId(), year, month);
                log.error("错误信息：", e);
                parkingRentArrearsService.add(entity.getId(), entity.getRentFee(), yearMonth, e.getShortMessage(), entity.getBuildingId());
            } catch (Exception e) {
                log.error("车位租金划扣失败：rentId[{}], year[{}], month[{}]", entity.getId(), year, month);
                log.error("错误信息：", e);
                parkingRentArrearsService.add(entity.getId(), entity.getRentFee(), yearMonth, "划扣失败", entity.getBuildingId());
            }
        }

        parkingRentDeductionService.complete(villageId, year, month);


        log.info("车位租金划扣完成");
    }

    public CustomPage<ParkingRentPayVo> payPage(Long pageNo, Long pageSize, Integer villageId, Integer building, Integer unit, String roomNumber, LocalDate startDate, LocalDate endDate) {
        Page<ParkingRentPayVo> page = new Page<>(pageNo, pageSize);

        LocalDateTime startTime = null;
        LocalDateTime endTime = null;

        if (startDate != null) {
            startTime = DateUtil.startTime(startDate);
        }

        if (endDate != null) {
            endTime = DateUtil.endTime(endDate);
        }

        IPage<ParkingRentPayVo> resultPage = parkingRentMapper.payPage(page, villageId, building, unit, roomNumber, startTime, endTime);

        return new CustomPage<>(resultPage);
    }

    @Transactional(rollbackFor = Exception.class)
    public void payDelete(Integer id) {
        ParkingRentPayRecordEntity payRecordEntity = parkingRentPayRecordService.getNormalById(id);
        ParkingRentEntity rent = getById(payRecordEntity.getRentId());
        if (ParkingRentPayRecordEntity.TYPE_NORMAL.equals(payRecordEntity.getType())) {
            payDeleteNormal(rent, payRecordEntity);
        } else {
            payDeleteArrears(rent, payRecordEntity);
        }
    }

    private void payDeleteNormal(ParkingRentEntity rentEntity, ParkingRentPayRecordEntity payEntity) {
        parkingRentPayRecordService.delete(payEntity.getId());

        walletService.deposit(rentEntity.getBuildingId(), payEntity.getAdvance(), WalletType.PARKING);

        String yearMonth = payEntity.getRemark().substring(0, 6);

        parkingRentArrearsService.add(rentEntity.getId(), rentEntity.getRentFee(), yearMonth, "批量划扣删除", rentEntity.getBuildingId());

    }

    private void payDeleteArrears(ParkingRentEntity rentEntity, ParkingRentPayRecordEntity payEntity) {
        parkingRentPayRecordService.delete(payEntity.getId());
        //缴费时使用了预存，则增加预存
        if (payEntity.getAdvance().compareTo(BigDecimal.ZERO) > 0) {
            walletService.deposit(rentEntity.getBuildingId(), payEntity.getAdvance(), WalletType.PARKING);
        }
        //缴费时转存了预存，则减少预存
        if (payEntity.getAdvanceReturn().compareTo(BigDecimal.ZERO) > 0) {
            walletService.updateExpenditure(rentEntity.getBuildingId(), payEntity.getAdvanceReturn(), WalletType.PARKING);
        }


        parkingRentArrearsService.undoCharge(payEntity.getId());

    }

    public void payExport(Integer villageId, Integer building, Integer unit, String roomNumber, LocalDate startDate, LocalDate endDate, HttpServletRequest request, HttpServletResponse response) {

        CustomPage<ParkingRentPayVo> parkingRentPayVoCustomPage = payPage(1L, 1000000L, villageId, building, unit, roomNumber, startDate, endDate);

        List<ParkingRentPayVo> parkingRentPayVos = parkingRentPayVoCustomPage.getRecord();

        try {
            XSSFWorkbook wb = new XSSFWorkbook(new FileInputStream(tempFilePath));
            // 根据页面index 获取sheet页
            XSSFSheet sheet = wb.getSheetAt(0);

            for (int i = 0; i < parkingRentPayVos.size(); i++) {
                XSSFRow rw = sheet.createRow(i + 1);
                setCell(parkingRentPayVos.get(i), rw);
            }

            ExportUtil.exportExcel(request, response, "车位租金缴费记录.xlsx", wb);
        } catch (IOException e) {
            throw new SystemException("导出失败", e);
        }
    }

    public PayBillVo payBill(Integer id) {

        ParkingRentPayVo parkingRentPayVo = parkingRentMapper.payVo(id);

        PayBillVo payBillVo = new PayBillVo();

        payBillVo.setTitle(patee + "收款收据");

        payBillVo.setBillNo(parkingRentPayVo.getBillNo());

        payBillVo.setVillageName(parkingRentPayVo.getVillageName());

        payBillVo.setAddress(parkingRentPayVo.getBuilding() + "-" + parkingRentPayVo.getUnit() + "-" + parkingRentPayVo.getRoomNumber());

        payBillVo.setOwnerName(parkingRentPayVo.getUserName());

        payBillVo.setPayTime(parkingRentPayVo.getPayTime().toLocalDate());

        payBillVo.setFeeType("车位租金");

        payBillVo.setMoney(parkingRentPayVo.getMoney());

        payBillVo.setAdvanceBalance(parkingRentPayVo.getAdvanceRemain());

        payBillVo.setRemark(parkingRentPayVo.getRemark());

        payBillVo.setRealAmount(parkingRentPayVo.getMoney());

        payBillVo.setChineseAmount(NumberToCn.number2Cn(parkingRentPayVo.getMoney()));

        payBillVo.setPayee(parkingRentPayVo.getPayee());

        payBillVo.setReceiveUnit(receiveUnit);

        return payBillVo;
    }

    public ParkingRentEntity getById(Integer id) {
        return parkingRentMapper.selectById(id);
    }

    private List<ParkingRentEntity> getByVillageId(Integer villageId) {

        return parkingRentMapper.getByVillageId(villageId);
    }

    /**
     * 根据楼栋编号查询在租的车位
     *
     * @param buildingId 楼栋编号
     * @return 在租车位
     */
    private ParkingRentEntity findRentingByBuildingId(Integer buildingId) {
        QueryWrapper<ParkingRentEntity> wrapper = new QueryWrapper<>();
        wrapper.eq("building_id", buildingId);
        wrapper.eq("state", ParkingRentEntity.STATE_RENTING);
        return parkingRentMapper.selectOne(wrapper);
    }

    private void setCell(ParkingRentPayVo parkingRentPayVo, XSSFRow row) {
        row.createCell(0).setCellValue(parkingRentPayVo.getVillageName());
        row.createCell(1).setCellValue(parkingRentPayVo.getBuilding() + "栋-" + parkingRentPayVo.getUnit() + "单元-" + parkingRentPayVo.getRoomNumber());
        row.createCell(2).setCellValue(parkingRentPayVo.getMoney().doubleValue());
        row.createCell(3).setCellValue(parkingRentPayVo.getParkingNo());
        row.createCell(4).setCellValue(parkingRentPayVo.getParkingNum());
        row.createCell(5).setCellValue(parkingRentPayVo.getPayTypeInfo());
        row.createCell(6).setCellValue(parkingRentPayVo.getAdvance().doubleValue());
        row.createCell(7).setCellValue(parkingRentPayVo.getCash().doubleValue());
        row.createCell(8).setCellValue(parkingRentPayVo.getAdvanceRemain().doubleValue());
        row.createCell(9).setCellValue(DateUtil.fromLocalDateTime(parkingRentPayVo.getPayTime()));
        row.createCell(10).setCellValue(parkingRentPayVo.getRemark());
    }

    @Autowired
    public void setParkingRentMapper(ParkingRentMapper parkingRentMapper) {
        this.parkingRentMapper = parkingRentMapper;
    }

    @Autowired
    public void setParkingRentDeductionService(ParkingRentDeductionService parkingRentDeductionService) {
        this.parkingRentDeductionService = parkingRentDeductionService;
    }

    @Autowired
    public void setUserService(UserService userService) {
        this.userService = userService;
    }

    @Autowired
    public void setParkingRentPayRecordService(ParkingRentPayRecordService parkingRentPayRecordService) {
        this.parkingRentPayRecordService = parkingRentPayRecordService;
    }

    @Autowired
    public void setParkingRentArrearsService(ParkingRentArrearsService parkingRentArrearsService) {
        this.parkingRentArrearsService = parkingRentArrearsService;
    }

    @Autowired
    public void setSnowflakeIdWorker(SnowflakeIdWorker snowflakeIdWorker) {
        this.snowflakeIdWorker = snowflakeIdWorker;
    }

    @Autowired
    public void setWalletService(WalletService walletService) {
        this.walletService = walletService;
    }
}